import { Utils, Logger } from 'orion-common'
import Konva from 'konva'
import TUtils from './node-utils.js'
import TEntityNode from './node-entity.js'
import TRootNode from './node-root.js'

/**
 * 编辑面板
 */
class TStage {
  constructor(options) {

    this.options = Utils.lodash.merge({
      draggable: true,
      canZoom: true,
      canWheelZoom: true,
      readonly: false,
      showMouseInfo: false,
      uid: Utils.common.uniqid()
    }, options)

    this.options.type = 'stage'
    this.stage = new Konva.Stage({
      id: this.options.uid,
      name: this.options.type,
      width: this.options.width,
      height: this.options.height,
      container: this.options.container,
      draggable: this.options.draggable
    })
    this.stage.setAttr(`@${this.options.type}`, this)

    this.root = null

    this.layers = {}

    // 创建图层
    this.layers.model = new Konva.Layer()
    this.stage.add(this.layers.model)

    // 拖放层
    this.layers.hud = new Konva.Layer()
    this.stage.add(this.layers.hud)

    // 当前鼠标位置
    this.mousePos = {
      x: 0,
      y: 0
    }

    this.mouseInfo = new Konva.Text({
      x: 40,
      y: 20,
      align: 'center',
      verticalAlign: 'middle',
      text: `X: ${this.mousePos.x} Y: ${this.mousePos.y}`,
      fontSize: TUtils.label.fontSize,
      fill: TUtils.link.fill,
      visible: this.options.showMouseInfo,
      listening: false
    })
    this.layers.hud.add(this.mouseInfo)

    // 是否被修改
    this.modified = false

    // 是否允许缩放
    this.zoom = 1.0
    this.minZoom = 0.1
    this.maxZoom = 10
    this.zoomFactor = 1.25

    // 操作列表（用于Undo， Redo）
    this.maxAction = 50
    this.actions = []

    // 当前操作列表游标索引
    this.actionIndex = -1

    // 当前选中的节点
    this.select = null
    this.selectPos = null

    this.__dropEntity__ = null

    // 根节点
    this.addRootNode()

    // 鼠标事件
    let con = this.stage.container()
    con.addEventListener('dragover',  (evt) => {
      evt.preventDefault() // !important
    })

    con.addEventListener('drop', (evt) => {
      evt.preventDefault()

      // 获取标签信息
      if (!this.__dropEntity__) {
        Logger.error('Stage drop error: data is invalid')
        return
      }

      // now we need to find pointer position
      // we can't use stage.getPointerPosition() here, because that event
      // is not registered by Konva.Stage
      // we can register it manually:
      this.stage.setPointersPositions(evt)
      let pos = this.stage.getPointerPosition()

      // 判断当前所在实体
      let parent = this.rootNode()
      let shape = this.stage.getIntersection(pos)
      if (shape) {
        let node = this.findNodeParent(shape)
        if (node) {
          parent = node
        }
      }

      // 添加节点
      this.addNode('entity', this.__dropEntity__, parent)
      this.modified = true
    })
    
    this.stage.on('mousemove', () => {
      this.updateMouseInfo()
    })

    this.stage.on('dragstart', (evt) => {
      if (evt.target.hasName('node')) {
        let node = this.findNodeParent(evt.target)
        if (!node) {
          Logger.error('Stage dragstart error: node is invalid')
          return
        }

        let parent = node.parent()
        if (parent) {
          node.knode().setAttr('@drag', parent)
        } else {
          parent = node.knode().getAttr('@drag')
        }
        node.knode().setAttr('@dragIndex', -1)

        // 脱离原父子关系
        node.enterDragging()
        parent.adjust()
        parent.refresh()
      }
      evt.cancelBubble = true
    })

    this.stage.on('dragmove', (evt) => {
      this.updateMouseInfo()
      this.mouseInfo.setAbsolutePosition({
        x: 40,
        y: 20
      })

      if (evt.target.hasName('node')) {

        let node = this.findNodeParent(evt.target)
        if (!node) {
          Logger.error('Stage dragmove error: node is invalid')
          return
        }

        // 判断新的父节点, 发送dragenter事件
        let mousePos = this.stage.getPointerPosition()
        // 遍历实体
        let newParent = null
        let nodes = this.layers.model.find('.node')
        for (let n of nodes) {
          let entity = n.getAttr('@node')
          if (!entity.canAcceptChild() || entity.dragging()) continue

          let index = entity.intersection(mousePos)
          if (index >= 0) {
            newParent = entity
            node.knode().setAttr('@dragIndex', index)
            break
          }
        }

        if (!newParent) {
          newParent = this.root
        }

        let previousParent = node.knode().getAttr('@drag')
        if (newParent != previousParent) {
          // 切换连线
          previousParent.dropChild(null)
        }

        node.knode().setAttr('@drag', newParent)
        newParent.dropChild(node)
        this.refresh()
      }

      evt.cancelBubble = true
    })

    this.stage.on('dragend', (evt) => {
      if (evt.target.hasName('node')) {
        let node = this.findNodeParent(evt.target)
        if (!node) {
          Logger.error('Stage dragend error: node is invalid')
          return
        }

        // 原来父节点
        let parent = node.parent()
        let newParent = node.knode().getAttr('@drag')
        let index = node.knode().getAttr('@dragIndex')

        node.exitDragging()

        if (parent == newParent) {
          parent.insertChild(node, index)
          parent.adjust()
        } else {
          newParent.insertChild(node, index)
          newParent.adjust()
        }
        newParent.dropChild(null)
        newParent.expandChildren(true)
        newParent.refresh()
      }
      evt.cancelBubble = true
    })

    this.stage.draw()

    // focus
    this.cache = null
    let container = this.stage.container()
    // 阻止右键菜单
    container.oncontextmenu = function (evt) {
      evt.preventDefault()
    }
    container.tabIndex = 1
    container.focus()

    container.addEventListener('keydown', (evt) => {
      console.log(evt.key)
      if (evt.ctrlKey === true) {
        if (evt.key === 'C' || evt.key === 'c') { // C
          if (this.select && this.select !== this.root) { // Root节点不能复制 
            this.cache = Utils.common.clone(this.select.toJson())
            console.log('copy', this.cache)
          }
        } else if (evt.key === 'V' || evt.key === 'v') { // V
          if (this.cache) {
            // 判断当前选中节点
            let sel = this.selectedNode()
            if (sel.canAcceptChild()) {
              let n = this.createNode('entity', this.cache)
              if (n) {
                sel.addChild(n)
                this.snapshot()
              } else {
                return
              }
            }
          }
        } else {
          return
        }
      } 
      evt.preventDefault()
      this.layers.model.batchDraw()
    })
  }


  dropEntity(data) {
    this.__dropEntity__ = data
  }

  /**
   * 
   */
  updateMouseInfo() {
    let pos = this.stage.getPointerPosition()
    this.mousePos.x = pos.x
    this.mousePos.y = pos.y
    this.mouseInfo.text(`X: ${this.mousePos.x} Y: ${this.mousePos.y}`)
  }

  /**
   * 缓冲快照
   */
  snapshot() {
    if (this.actions.length >= this.maxAction) {
      this.actions.splice(0, 1)
    }

    // 一旦添加快照，删除当前undo队列后续缓存
    if (this.actionIndex >= 0 && this.actionIndex < this.actions.length - 1) {
      this.actions.splice(this.actionIndex + 1, this.actions.length - this.actionIndex - 1)
    }

    let cache = this.saveToJson()
    this.actions.push(cache)
    this.actionIndex = this.actions.length - 1
  }

  /**
   * 刷新显示
   */
  refresh() {

    if (this.options.showMouseInfo) {
      this.updateMouseInfo()
      this.mouseInfo.setAbsolutePosition({
        x: 40,
        y: 20
      })

      let cur = this.mouseInfo.scale()
      let scale = this.mouseInfo.getAbsoluteScale()
      this.mouseInfo.scaleX( cur.x / scale.x )
      this.mouseInfo.scaleY( cur.y / scale.y )
    }
    this.stage.batchDraw()
  }

  /**
   * 查找所在Group对象
   * @param shape
   * @returns {*}
   */
  findNodeParent(shape) {
    // 如果自己满足条件，返回自己
    let p = shape
    while (p) {
      if (p instanceof Konva.Group && p.hasName('node')) {
        break
      }
      p = p.getParent()
    }
    return p ? p.getAttr('@node') : null
  }

  /**
   * 添加根节点
   */
  addRootNode(config) {
    this.root = new TRootNode(Utils.lodash.merge({
      x: 20,
      y: this.stage.height() / 2,
      title: '场景'
    }, config))
    this.layers.model.add(this.root.knode())
  }

  /**
   * 返回根节点
   * @returns 
   */
  rootNode() {
    return this.root
  }

  /**
   * 根据ID获取Node
   * @param {*} uid string 为空则返回根节点
   */
  getNode(uid) {
    if (uid) {
      let nodes = this.layers.model.find('#' + uid)
      if (nodes.length > 0) {
        if (nodes.length !== 1) {
          Logger.warn(`TStage::getNode - Node <${uid}> is not unique`)
        }
        let node = nodes[0].getAttr('@node')
        if (node instanceof TEntityNode) {
          return node
        } else {
          Logger.error(`TStage::getNode - Node <${uid}> is not TEnittyNode`)
        }
      }
    }
    return this.root
  }

  /**
   * 改变大小
   * @param w
   * @param h
   */
  resize(w, h) {
    w && this.stage.width(w)
    h && this.stage.height(h)
    this.stage.draw()
  }

  /**
   * 放大
   */
  zoomIn() {
    if (!this.options.canZoom) {
      return
    }
    this.zoom = Utils.lodash.clamp(this.zoom * this.zoomFactor, this.minZoom, this.maxZoom)
    this.stage.scale({
      x: this.zoom,
      y: this.zoom
    })
    this.refresh()
  }

  zoomOut() {
    if (!this.options.canZoom) {
      return
    }
    this.zoom = Utils.lodash.clamp(this.zoom / this.zoomFactor, this.minZoom, this.maxZoom)
    this.stage.scale({
      x: this.zoom,
      y: this.zoom
    })
    this.refresh()
  }

  reset() {
    this.zoom = 1.0
    this.stage.scale({
      x: this.zoom,
      y: this.zoom
    })
    this.stage.position({
      x: 0,
      y: 0
    })
    this.refresh()
  }

  /**
   * 获取当前选中节点，如果没有则返回根节点
   */
  selectedNode() {
    return this.select ? this.select : this.root
  }

  /**
   * 设置当前选中节点
   * @param {*} node 
   */
  selectNode(node) {
    if (this.select !== node) {
      if (this.select) {
        this.select.selected(false)
      }
      this.select = node
      if (this.select) {
        this.selectPos = this.stage.getPointerPosition()
        this.select.selected(true)
      }
    }
    this.refresh()
  }

  /**
   * 清空编辑器，不能撤销
   * @param cache boolean 是否清除快照缓冲
   */
  clear(cache = true) {
    // 是否被修改
    this.modified = false

    // 清除缓存
    if (cache) {
      this.actions = []
      // 当前操作列表游标索引
      this.actionIndex = -1
    }

    this.select = null

    // 删除根节点
    this.root.selected(false)
    this.root.clearChildren()

    this.refresh()
  }

  /**
   * 
   * @param {*} config 
   */
  createNode(type, config = {}) {
    let node = null
    if (type === 'entity') {
      node = new TEntityNode(config)
    }

    if (!node) {
      Logger.error(`TStage::addEnity failed - unknown node : ${type}`)
      return null
    }

    // 创建子节点
    if (config.children) {
      for (let child of config.children) {
        let n = this.createNode('entity', child)
        if (!n) {
          continue
        }
        node.addChild(n, false)
      }
    }

    return node
  }

  /**
   * 给当前选择节点上添加子节点
   * @param {*} config 
   * @param {*} parent 
   */
  addNode(type, config = {}, parent = null) {
    let child = this.createNode(type, config)
    if (!child) return

    if (!parent) {
      parent = this.selectedNode()
    }
    parent.addChild(child)
    this.refresh()
  }

  /**
   * 加载模型
   * @param data 快照数据
   * @param cache  boolean 是否清除快照缓冲
   */
  loadFromJson(data, cache = true) {
    // 清空面板
    this.clear(cache)

    if (!data) {
      return
    }

    // 解析读取data
    // 根节点
    let top = null
    if (data.root) {
      top = this.createEntity(data.root)
      if (!top) {
        Logger.error('TStage::loadFromJson failed - data.root is currupted')
        return
      }
      this.root.addChild(top)
    } else {
      Logger.warn('TStage::loadFromJson - data is null')
      return
    }

    this.root.adjust({
      downward: true
    })

    // 如果清除之前缓存，则重新构建新缓存
    if (cache) {
      this.snapshot()
    }

    this.refresh()
  }

  /**
   * 保存模型
   */
  saveToJson() {
    let json = {}
    let top = this.root.children[0]
    if (top) {
      json.root = top.toJson()
    }
    return Utils.common.clone(json)
  }

  /**
   * 保存为Image
   */
  saveToImage() {

  }

  /**
   * 是否有undo
   * @returns {boolean}
   */
  hasUndo() {
    return this.actions.length > 1 && this.actionIndex > 0
  }

  /**
   * 撤销
   */
  undo() {
    if (this.actions.length <= 1) {
      this.actionIndex = this.actions.length - 1
      return
    }

    if (this.actionIndex < 0) {
      this.actionIndex = this.actions.length - 1
    }

    if (this.actionIndex > 0) {
      this.actionIndex -= 1
      let cache = this.actions[this.actionIndex]
      // 加载之前缓冲（保留缓冲队列）
      this.loadFromJson(cache, false)
    }
  }

  /**
   * 是否有redo
   * @returns {boolean}
   */
  hasRedo() {
    return this.actionIndex >= 0 && (this.actionIndex < this.actions.length - 1)
  }

  /**
   * 重做
   */
  redo() {
    if (this.actionIndex < 0) {
      return
    }

    if (this.actionIndex < this.actions.length - 1) {
      this.actionIndex += 1
      let cache = this.actions[this.actionIndex]
      // 加载之前缓冲（保留缓冲队列）
      this.loadFromJson(cache, false)
    }
  }

  /**
   * 
   */
  isReadOnly() {
    return this.options.readonly
  }

  isDebug() {
    return this.options.debug
  }

  randomColor() {
    let index = Math.round((Math.random() * 1000)) % TUtils.colors.length
    return TUtils.colors[index]
  }

}

export default TStage